package de.bazinga.rotw.collision;

import java.util.Enumeration;
import java.util.Vector;

import com.jme.math.Vector3f;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Box;
import com.jmex.game.state.GameStateManager;
import com.jmex.jbullet.nodes.PhysicsNode;
import com.jmex.terrain.TerrainBlock;

import de.bazinga.rotw.game.RotwGameState;
import de.bazinga.rotw.person.OpponentList;
import de.bazinga.rotw.person.Person;
import de.bazinga.rotw.vehicle.Vehicle;

public class CollisionHandler {

	private Spatial collisionSpatial = null;
	
	private Person collisionPerson = null;
	private Vehicle collisionVehicle = null;
	
	public CollisionHandler(Spatial collisionSpatial) {
		this.collisionSpatial = collisionSpatial;
	}
	
	public boolean collisionWithObject() {
		Vector<Spatial> object = CollidableObjects.getInstance().getObjects("object");
		if(object != null) {
			for(Spatial o:object) {
				if(collisionSpatial.hasCollision(o, false)) {
					return true;
				}
			}
		}
		return false;
	}
	
	public boolean collisionWithPhysicsObject() {
		Vector<Spatial> object = CollidableObjects.getInstance().getObjects("physics");
		if(object != null) {
			for(Spatial o:object) {
				if(collisionSpatial.hasCollision(o, false)) {
					return true;
				}
			}
		}
		return false;
	}
	

	public boolean collisionWithOpponent(Person player) {
		setCollisionPerson(null);
		
		
		Enumeration<Person> e = OpponentList.getInstance().getOpponents().elements();
		while(e.hasMoreElements()) {
			Person opp = e.nextElement();
			if(player == null || opp != player) {
				if(collisionSpatial.hasCollision(opp, true)) {
					setCollisionPerson(opp);
					return true;
				}
				
			}
		}
		return false;
	}
	
	public boolean collisionWithVehicle() {
		Vector<Spatial> vehicles = CollidableObjects.getInstance().getObjects("vehicle");
		if(vehicles == null) return false;
		
		for(Spatial car:vehicles) {
			if(collisionSpatial.hasCollision(car, true)) {
				setCollisionVehicle((Vehicle)car);
				return true;
			}
		}
		return false;
	}
	
	
	public boolean collisionWithWall() {
		Vector<Spatial> walls = CollidableObjects.getInstance().getObjects("wall");
		if(walls != null) {
			for(Spatial b:walls) {
				if(collisionSpatial.hasCollision(b, false)) {
					return true;
				}
			}
		}
		return false;
	}

	
	
	public boolean collisionWithGround() {
		Vector<Spatial> walls = CollidableObjects.getInstance().getObjects("groundNode");
		if(walls != null) {
			for(Spatial b:walls) {
				if(collisionSpatial.hasCollision(b, false)) {
					return true;
				}
			}
		}
		return false;
	}
	

	
	public boolean collisionWithTerrain() {
		TerrainBlock tb = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getTerrainBlock();
		if(tb == null) return false;
		
		if(tb.hasCollision(collisionSpatial, true)) {
			return true;
		}
		
		return false;
	}
	
	public boolean collisionWithTerrainRay() {
		TerrainBlock tb = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getTerrainBlock();
		PhysicsNode tbP = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getTerrainPhysicsNode();
		if(tb == null) return false;
		
		
		float terrainHeight = tb.getHeightFromWorld(
				collisionSpatial.getLocalTranslation().subtract(tbP.getLocalTranslation())) + tbP.getLocalTranslation().getY();
		float playerHeight = collisionSpatial.getLocalTranslation().getY();
		
		if (!Float.isInfinite(terrainHeight) && !Float.isNaN(terrainHeight)) {
        	if(playerHeight > (terrainHeight - 0.3f) && playerHeight < (terrainHeight + 0.3f)) {
        		return true;
    		}
		}
		
		return false;
	}
	
	
	public float getTerrainHeightDifference(Vector3f oldLocation) {
		TerrainBlock tb = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getTerrainBlock();
		PhysicsNode tbP = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getTerrainPhysicsNode();
		if(tb != null) {
			float terrainHeight = tb.getHeightFromWorld(
					collisionSpatial.getLocalTranslation().subtract(tbP.getLocalTranslation())) + tbP.getLocalTranslation().getY();
			float terrainHeightPrev = tb.getHeightFromWorld(
					oldLocation.subtract(tbP.getLocalTranslation())) + tbP.getLocalTranslation().getY();
			
			if (!Float.isInfinite(terrainHeight) && !Float.isNaN(terrainHeight)) {
				return (terrainHeight - terrainHeightPrev);
	        }
		}
		return 0;
	}
	
	public float getTerrainHeight() {
		TerrainBlock tb = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getTerrainBlock();
		PhysicsNode tbP = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getTerrainPhysicsNode();
		if(tb != null) {
			float terrainHeight = tb.getHeightFromWorld(
					collisionSpatial.getLocalTranslation().subtract(tbP.getLocalTranslation())) + tbP.getLocalTranslation().getY();
			
			return terrainHeight;
		}
		return Float.NaN;
	}
	
	
	public float collisionWithWallStep(float maxStepSize) {
		Vector<Spatial> walls = CollidableObjects.getInstance().getObjects("wall");
		float newY = -999;
		if(walls != null) {
			for(Spatial b:walls) {
				if(collisionSpatial.hasCollision(b, false)) {
					
					float boxTopY = (((Box)b).getCenter().y + ((Box)b).getYExtent());
					
					if( Math.abs(collisionSpatial.getLocalTranslation().getY() - boxTopY) <= maxStepSize ) {
						newY = boxTopY;
					}else{
						return -1000;
					}
				}
			}
		}
		return newY;
	}

	public void setCollisionPerson(Person collisionPerson) {
		this.collisionPerson = collisionPerson;
	}

	public Person getCollisionPerson() {
		return collisionPerson;
	}

	public void setCollisionVehicle(Vehicle collisionVehicle) {
		this.collisionVehicle = collisionVehicle;
	}

	public Vehicle getCollisionVehicle() {
		return collisionVehicle;
	}
}
